package common

import (
	"crypto/sha256"
	"encoding/json"
	"github.com/eywa-protocol/bls-crypto/bls"
)

type Transaction struct{
	TxId     []byte
	Input    []UTXO
	Output   []UTXO
	Sigs     []bls.Signature
	LockTime int
}

func TxTest() {
	pr, pu := bls.GenerateRandomKey();
	inputs := []UTXO{{pu, []byte("12"), 10}}
	outputs := []UTXO{{pu, []byte("123"), 10}}

	var tx = Transaction{
		[]byte("123"),
		inputs,
		outputs,
		[]bls.Signature{},
		0,
	}

	msg := tx.GetMsg()
	sig := pr.Sign(msg)

	sigs := []bls.Signature{sig}
	tx.Sigs = sigs

	if tx.Verify() {
		println("tx verify success")
	} else {
		println("tx verify fail")
	}

	// unmarshal test
	var newTx Transaction
	err := json.Unmarshal(msg, &newTx)
	if err != nil {
		err.Error()
	}
	newTx.Sigs = sigs
	if newTx.Verify() {
		println("tx unmarshal success")
	} else {
		println("tx unmarshal fail")
	}

	// mul-sig test
	pr1, pu1 := bls.GenerateRandomKey()
	pr2, pu2 := bls.GenerateRandomKey()

	prSet := []bls.PrivateKey{pr1, pr2}
	puSet := pu1.Aggregate(pu2)

	s := tx.MultiSign(prSet)
	if s.Verify(puSet, msg) {
		println("mul-sig success")
	} else {
		println("mul-sig fail")
	}

}

func NewTransaction(id []byte, in []UTXO, out []UTXO, sigs []bls.Signature, t int) Transaction {
	return Transaction{
		id,
		in,
		out,
		sigs,
		t,
	}
}

// 通过输入输出UTXO构造交易
func GenerateTransactionByUTXO(inputUTXOs []UTXO, outputUTXOs []UTXO, lockTime int) *Transaction{
	tran := new(Transaction)
	tran.Input = inputUTXOs[:]
	tran.Output = outputUTXOs[:]
	tran.LockTime = lockTime

	// 计算transactionID
	msg,_ := json.Marshal(tran)
	s_ob:=sha256.New()
	s_ob.Write(msg)
	hash:=s_ob.Sum(nil)

	// 将transactionID
	tran.TxId = hash[:]
	for i:=0;i<len(outputUTXOs);i++ {
		tran.Output[i].Tx_id = hash[:]
	}

	return tran
}

// sign and verify
func (tx Transaction) GetMsg() []byte {
	tempTx := NewTransaction(tx.TxId, tx.Input, tx.Output, nil, tx.LockTime)
	msg,_ := json.Marshal(tempTx)

	return msg
}

// return true if the tx is legal
func (tx Transaction) Verify() bool {
	msg := tx.GetMsg()
	for i:=0; i < len(tx.Input); i ++ {
		if !tx.Sigs[i].Verify(tx.Input[i].PublicKey, msg){

			if len(tx.Sigs) == 3 {
				println("error index = ", i)
			}

			return false
		}
	}
	return true
}

func (tx *Transaction) Sign(key bls.PrivateKey) bls.Signature{
	return key.Sign(tx.GetMsg())
}

func (tx *Transaction) MultiSign(keys []bls.PrivateKey) bls.Signature{
	msg := tx.GetMsg()

	sig := keys[0].Sign(msg)
	for i:=1; i<len(keys); i++ {
		temp := keys[i].Sign(msg)
		sig = sig.Aggregate(temp)
	}

	return sig
}

// json 同样可以使用自生成的marshal和unmarshal
